package mroute

import (
	"github.com/gin-gonic/gin"
	"mygo/mymongo"
	"mygo/mystruct"
	"path/filepath"
	"os"
	"fmt"
	"time"
	"strconv"
	"strings"
	"encoding/json"
	"mygo/myws"
	"mygo/mylog"
	"net/http"
	"mygo/global"
	"mygo/mroute/utils"
)


/* =================================================================================
   其它接口
*/
// 文件下载
func Mydownload(cont *gin.Context) {
	apiid := cont.DefaultQuery("code","")
	codb := mymongo.Get_Code(apiid)
	if codb == nil {
		cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "标识不存在"})
		return
	}
	queryid := cont.DefaultQuery("_id", "")
	cont.Header("Content-Type", "application/octet-stream")
	cont.Header("Content-Transfer-Encoding", "binary")
	cont.Header("Cache-Control", "no-cache")
	for key, values := range cont.Request.URL.Query() {
		if key != "code" && key != "_id" {
			file_Path := filepath.Join(global.Mtoken.Download_Path, codb.Body.Apiid, queryid, key, values[0])
			cont.Header("Content-Disposition", "attachment; filename=" + values[0])
			cont.Header("Content-Length", fmt.Sprintf("%d", mystruct.GetFileSize(file_Path)))
			cont.Header("X-MD5-Checksum", mystruct.GetMD5OfFile(file_Path))
			cont.Header("X-SHA256-Checksum", mystruct.GetSHA256fFile(file_Path))
			if mystruct.Exists(file_Path) {
		      http.ServeFile(cont.Writer, cont.Request, file_Path)
			}else{
				cont.Redirect(mystruct.StatusNotFound, "/404")
			}
		}
	}
		
   json_data, _ := json.Marshal(map[string]string{
		"apiid": apiid,
		"_id": queryid,
	})
	mesg := myws.Mesg{
		Type: "Download",
		Api: "/api/download",
		Data: json_data,
	}
	mylog.MyLog(mesg, cont.Request.RemoteAddr, global.Mtoken.Log_Path)
}
// 文件信息查询
func FileHead(cont *gin.Context) {
	apiid := cont.DefaultQuery("code","")
	queryid := cont.DefaultQuery("_id", "")
	for key, values := range cont.Request.URL.Query() {
		if key != "code" && key != "_id" {
			file_Path := filepath.Join(global.Mtoken.Download_Path, apiid, queryid, key, values[0])
			cont.Header("Content-Type", "application/json")
			cont.Header("Content-Length", fmt.Sprintf("%d", mystruct.GetFileSize(file_Path)))
			cont.Header("X-MD5-Checksum", mystruct.GetMD5OfFile(file_Path))
			cont.Header("X-SHA256-Checksum", mystruct.GetSHA256fFile(file_Path))
			cont.Status(mystruct.StatusOK)
		}
	}
	
}
func MyExTable(cont *gin.Context) {
	code := cont.DefaultQuery("code", "")
	codb := mymongo.Get_Code(code)
	if codb == nil {
		cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "表不存在"})
		return
	}
	jsonData, err := json.MarshalIndent(codb.Body, "", "    ")
	if err != nil {
		cont.JSON(mystruct.StatusInternalServerError, gin.H{"status": "error", "message": "JSON序列化失败"})
		return
	}
	cont.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s.json", code))
	cont.Header("Content-Length", strconv.Itoa(len(jsonData)))
	cont.Data(mystruct.StatusOK, "application/octet-stream", []byte(jsonData))
}
// 数据导出
func MyExport(cont *gin.Context) {
	map_list := make(map[string]string)
	map_list["start_time"] = cont.DefaultQuery("start_time", "")
	map_list["stop_time"]  = cont.DefaultQuery("stop_time", "")
	map_list["expone"]     = cont.DefaultQuery("expone", "")
	map_list["expcond"]    = cont.DefaultQuery("expcond", "")
	map_list["exptype"]	  = cont.DefaultQuery("exptype", "")
	map_list["apiid"] 	  = cont.DefaultQuery("code", "")

	codb := mymongo.Get_Code(map_list["apiid"])
	if codb == nil {
		cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "表不存在"})
		return
	}
	fileName := fmt.Sprintf("%s.%s", time.Now().Format("2006-01-02_15-04-05"), map_list["exptype"])
	content, exptype := mymongo.Export(codb, map_list)
	var err error
	switch exptype {
	case "csv":
		err = utils.StreamCSVToWriter(cont, content, fileName)
	case "txt":
		err = utils.StreamTXTToWriter(cont, content, fileName, '\t')
	case "xls":
		err = utils.StreamXLSXToWriter(cont, content, fileName)
	}
	//cont.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fileName))
	//cont.Data(mystruct.StatusOK, "application/octet-stream", []byte(content))
	if err != nil {
        if !cont.Writer.Written() {
            cont.JSON(http.StatusInternalServerError, gin.H{"error": "export failed"})
        }
    }
	// 日志记录
	json_data, _ := json.Marshal(map_list)
	mesg := myws.Mesg{
		Type: "Export",
		Api: "/api/export",
		Data: json_data,
	}
	mylog.MyLog(mesg, cont.Request.RemoteAddr, global.Mtoken.Log_Path)
}
// 上传文件
func Myupfile(cont *gin.Context) {
	apiid   := cont.PostForm("apiid")
	field   := cont.PostForm("field")
	_id     := cont.PostForm("_id")
	model   := cont.DefaultPostForm("model", "push")
	file, err := cont.FormFile(field)
	if err != nil {
		cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": fmt.Sprintf("字段 [ %s ] 获取文件失败 【%s】", field, err.Error())})
		return
	}
	res, ret := mymongo.MyMonDB.ApiCur.Get(apiid)
	if res.Code != 1 {
		cont.JSON(mystruct.StatusOK, gin.H{"code": res.Code, "msg": res.Mesg})
		return
	}
	switch model {
		case "push":
			mfile_path := filepath.Join(global.Mtoken.File_Path, apiid, _id, field)
			if mystruct.Exists(mfile_path) == false {
				os.MkdirAll(mfile_path, os.ModePerm)
			}
			err = cont.SaveUploadedFile(file, filepath.Join(mfile_path, file.Filename))
			if err != nil {
				cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": err.Error()})
				return
			}
			cont.JSON(mystruct.StatusOK, gin.H{"code": res.Code, "msg": ret})

		case "load":
			fileType := strings.ToLower(filepath.Ext(file.Filename))
			if fileType != ".txt" && fileType != ".csv" && fileType != ".xls" {
				cont.JSON(mystruct.StatusBadRequest, gin.H{"error": "文件类型错误"})
				return
			}
			fileContent, err := file.Open()
			if err != nil {
				cont.JSON(mystruct.StatusInternalServerError, gin.H{"error": "打开文件失败"})
				return
			}
			defer fileContent.Close()
			codb := mymongo.Get_Code(apiid)
			var data []interface{}
			switch fileType {
				case ".txt":
					data, err = mystruct.ReadTxtFile(fileContent, codb.Body.Data)
				case ".csv":
					data, err = mystruct.ReadCsvFile(fileContent, codb.Body.Data)
				case ".xls":
					data, err = mystruct.ReadXlsFile(fileContent, codb.Body.Data)
			}
			if err != nil {
				cont.JSON(mystruct.StatusInternalServerError, gin.H{"error": fmt.Sprintf("文件转换失败: %v", err)})
				return
			}
			ret := mymongo.Append_All(data, codb)
			cont.JSON(mystruct.StatusOK, gin.H{"code": ret.Code, "msg": ret.Mesg})

		default:
			cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "参数错误"})
			return
	}
	// 日志记录
	json_data, _ := json.Marshal(map[string]string{"apiid":apiid, "field":field, "_id":_id, "name":file.Filename})
	mesg := myws.Mesg{
		Type: "pushfile",
		Code: res.Code,
		Api: "/api/push",
		Msg: res.Mesg,
		Data: json_data,
	}
	mylog.MyLog(mesg, cont.Request.RemoteAddr, global.Mtoken.Log_Path)
}